非UI线程可以更新UI?

前言

我们都知道,不能在非UI线程中更新UI,但是今天再次接触Handle,实验的时候,发现了一个很奇妙的问题,于是记录一下。

1
2
3
4
5
6
7
8
9
10
11
12
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.tv_result);
new Thread(){
@Override
public void run() {
mTextView.setText("2333");
}
}.start();
}

你猜猜执行会怎么着?竟然不会Crash,但是以下代码就会Crash。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.tv_result);
new Thread(){
@Override
public void run() {
try {
Thread.sleep(2000);
mTextView.setText("2333");
} catch (InterruptedException e) {
e.printStackTrace();
}
// mTextView.setText("2333");
}
}.start();
}

难道说和线程休眠有关?也不会呀,休不休眠它还是在非UI线程之中呀。那问题出在哪里了呢?

原因竟然是

在做UI更新的时候,会执行当前线程是否是UI线程的检查,即通过检查ViewRoot的线程和当前线程是否一致来判断是否是UI线程,一般来说,WiewRoot所在的线程就是UI线程。在OnCreate()的时候,ViewRoot还没有被创建,所以没法执行检查是否是UI线程。那在什么时候ViewRoot会被创建呢?答案是在执行onResume完成后,ViewRoot就能创建好了,这个时候就会执行UI线程检查了。

验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.tv_result);
mButtonTest = (Button) findViewById(R.id.btn_test);
mThread = new Thread() {
@Override
public void run() {
mTextView.setText("onCreate");
}
};
mButtonTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mThread.start();
}
});
Log.i("2333", "onCreate");
}
@Override
protected void onStart() {
super.onStart();
new Thread(){
@Override
public void run() {
mTextView.setText("onStart");
}
}.start();
Log.i("2333", "onStart");
}
@Override
protected void onResume() {
super.onResume();
new Thread(){
@Override
public void run() {
mTextView.setText("onResume");
}
}.start();
Log.i("2333", "onResume");
}
@Override
protected void onStop() {
super.onStop();
new Thread(){
@Override
public void run() {
mTextView.setText("onStop");
}
}.start();
Log.i("2333", "onStop");
}

根据打印的Log我们就能知道,是在onResume执行完之后才会进行UI线程的检查,参考的博客实际上是说执行到onResume就会检查了,看来还是自己动手实验一下比较有说服力。

参考:

http://bbs.csdn.net/topics/390871177?page=1

http://michaelye1988.iteye.com/blog/1923093

由源码分析可见以下:

http://www.cnblogs.com/yydcdut/p/3864072.html

保持好奇心!

我们一直都向往,面朝大海,春暖花开。 但是几人能做到,心中有爱,四季不败?